package com.ruoyi.ucar.service.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.ucar.boresp.OcrBrandPriceListBo;
import com.ruoyi.ucar.boresp.OcrDrivingLicenseBoResp;
import com.ruoyi.ucar.boresp.OcrVehicleRegistrationBoResp;
import com.ruoyi.ucar.boresp.VinBrandBoResq;
import com.ruoyi.ucar.constants.UcarConstants;
import com.ruoyi.ucar.domain.TBrandPrice;
import com.ruoyi.ucar.domain.TProduct;
import com.ruoyi.ucar.domain.TVehicleInfo;
import com.ruoyi.ucar.mapper.TBrandPriceMapper;
import com.ruoyi.ucar.mapper.TProductMapper;
import com.ruoyi.ucar.mapper.TVehicleInfoMapper;
import com.ruoyi.ucar.service.UCarOcrService;
import com.ruoyi.ucar.util.CommonUtil;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.net.URLEncoder;
import okhttp3.*;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.io.*;


@Service
public class UCarOcrServiceImpl implements UCarOcrService {

    @Value("${ucar.ocr.appid}")
    private String ocrAppId;
    @Value("${ucar.ocr.appkey}")
    private String ocrAppKey;
    @Value("${ucar.ocr.secretKey}")
    private String ocrSecretKey;
    @Value("${ucar.ocr.vinIdentifyKey}")
    private String vinIdentifyKey;

    @Value("${ucar.ocr.vinIdentifyUrl}")
    private String vinIdentifyUrl;
    @Autowired
    private   TBrandPriceMapper tBrandPriceMapper;

    @Autowired
    private TProductMapper tProductMapper;

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());


    @Autowired
    private TVehicleInfoMapper tVehicleInfoMapper;

    private List<OcrBrandPriceListBo> getOcrBrandPriceList(String brandModel){

        List<String> productTypes = Arrays.asList("uCarPreciseQuery", "uCarQueryMainten");
        List<TBrandPrice>  brandPriceList= tBrandPriceMapper.selectList
              (new LambdaQueryWrapper<TBrandPrice>().eq(TBrandPrice::getDeleteFlag,1l).in(TBrandPrice::getProductType,productTypes));
        List<OcrBrandPriceListBo> ocrBrandPriceListBos=new ArrayList<>();
       if(StringUtils.isNotNull(brandPriceList)&&brandPriceList.size()>0){
           for (TBrandPrice brandPrice:brandPriceList){
               if(UcarConstants.specialBrand.contains(brandModel)) {
                   if (brandModel.equals(brandPrice.getVehicleBrand())) {
                       OcrBrandPriceListBo ocrBrandPriceListBo = CommonUtil.objToObj(brandPrice, OcrBrandPriceListBo.class);
                       ocrBrandPriceListBo.setProductTypeDict(DictUtils.getDictLabel("product_type", brandPrice.getProductType()));
                       ocrBrandPriceListBos.add(ocrBrandPriceListBo);
                   }
               }else{
                   if (brandModel.contains(brandPrice.getVehicleBrand())) {
                       OcrBrandPriceListBo ocrBrandPriceListBo = CommonUtil.objToObj(brandPrice, OcrBrandPriceListBo.class);
                       ocrBrandPriceListBo.setProductTypeDict(DictUtils.getDictLabel("product_type", brandPrice.getProductType()));
                       ocrBrandPriceListBos.add(ocrBrandPriceListBo);
                   }
               }
           }
       }
        productTypes = Arrays.asList("lemonQueryAccident", "cheXinMengQueryAccident","batteryReport","cloudCheckTable");
        List<TProduct>  productList= tProductMapper.selectList(new LambdaQueryWrapper<TProduct>().
                eq(TProduct::getDeleteFlag,1l).in(TProduct::getProductType,productTypes));
        for (TProduct tProduct:productList){
                OcrBrandPriceListBo ocrBrandPriceListBo=new OcrBrandPriceListBo();
                ocrBrandPriceListBo.setProductType(tProduct.getProductType());
                ocrBrandPriceListBo.setProductTypeDict(DictUtils.getDictLabel("product_type",tProduct.getProductType()));
                ocrBrandPriceListBo.setPrice(tProduct.getProductPrice());
                ocrBrandPriceListBo.setRealPrice(tProduct.getProductRealPrice());
                ocrBrandPriceListBo.setPurchasingPrice(tProduct.getProductPurchasingPrice());
                ocrBrandPriceListBo.setReturnPrice(tProduct.getProductReturnPrice());
                ocrBrandPriceListBos.add(ocrBrandPriceListBo);
        }
        return ocrBrandPriceListBos;
    }

    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().readTimeout(300, TimeUnit.SECONDS).build();

    @Override
    public OcrDrivingLicenseBoResp ocrDrivingLicenseRecognition(InputStream inputStream) {
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(mediaType,
                "detect_direction=false" +
                        "&unified=false" +
                        "&quality_warn=false" +
                        "&risk_warn=false" +
                        "&quality_warn=false"+
                        "&image="+ URLEncoder.encode(CommonUtil.convertBase64FromInput(inputStream)));
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_license?access_token=" + this.getAccessToken())
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Accept", "application/json")
                .build();
        Response response = null;
        OcrDrivingLicenseBoResp ocrDrivingLicenseboRes=new OcrDrivingLicenseBoResp();
        try {
            response = HTTP_CLIENT.newCall(request).execute();
            String result=response.body().string();
            logger.info("行驶证Ocr识别返回结果：{}",result);
            if(result.indexOf("words_result")>-1) {

                JSONObject jsonObject = new JSONObject(result).getJSONObject("words_result");
                String vinNo=jsonObject.getJSONObject("车辆识别代号").getString("words");
                VinBrandBoResq  vinBrandBoResq=this.vinIdentifyVehicle(vinNo);
                ocrDrivingLicenseboRes.setVinNo(vinNo);
                ocrDrivingLicenseboRes.setBrandModel(vinBrandBoResq.getBrandName());
                ocrDrivingLicenseboRes.setVehicleType(jsonObject.getJSONObject("车辆类型").getString("words"));
                ocrDrivingLicenseboRes.setEngineNO(jsonObject.getJSONObject("发动机号码").getString("words"));
                ocrDrivingLicenseboRes.setLicensePlateNumber(jsonObject.getJSONObject("号牌号码").getString("words"));

                List<OcrBrandPriceListBo>  ocrBrandPriceListBos=this.getOcrBrandPriceList(ocrDrivingLicenseboRes.getBrandModel());
                if(StringUtils.isNotNull(ocrBrandPriceListBos)&&ocrBrandPriceListBos.size()>0){
                    ocrDrivingLicenseboRes.setOcrBrandPriceListBos(ocrBrandPriceListBos);
                }
            }else{
                ocrDrivingLicenseboRes.setErrorCode(new JSONObject(result).getInt("error_code"));
                ocrDrivingLicenseboRes.setErrorMsg(new JSONObject(result).getString("error_msg"));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        return ocrDrivingLicenseboRes;
    }

    @Override
    public OcrVehicleRegistrationBoResp ocrVehicleRegistrationRecognition(InputStream inputStream) {
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(mediaType,   "image="+ URLEncoder.encode(CommonUtil.convertBase64FromInput(inputStream)));
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_registration_certificate?access_token=" + getAccessToken())
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Accept", "application/json")
                .build();
        OcrVehicleRegistrationBoResp ocrVehicleRegistrationboRes=new OcrVehicleRegistrationBoResp();
        try {
            Response response = HTTP_CLIENT.newCall(request).execute();
            String result=response.body().string();
            logger.info("机动车登记证书Ocr识别返回结果：{}",result);

            if(result.indexOf("words_result")>-1) {
                JSONObject jsonObject= new JSONObject(result).getJSONObject("words_result");
                String vinNo=jsonObject.getJSONObject("vin").getString("words");
                VinBrandBoResq  vinBrandBoResq=this.vinIdentifyVehicle(vinNo);
                ocrVehicleRegistrationboRes.setVinNo(vinNo);
                ocrVehicleRegistrationboRes.setBrandModel(vinBrandBoResq.getBrandName());
                ocrVehicleRegistrationboRes.setVehicleType(jsonObject.getJSONObject("vehicle_type").getString("words"));
                ocrVehicleRegistrationboRes.setEngineNO(jsonObject.getJSONObject("engine_num").getString("words"));
                ocrVehicleRegistrationboRes.setLicensePlateNumber(jsonObject.getJSONObject("registration_num").getString("words"));
                List<OcrBrandPriceListBo>  ocrBrandPriceListBos=this.getOcrBrandPriceList(ocrVehicleRegistrationboRes.getBrandModel());
                if(StringUtils.isNotNull(ocrBrandPriceListBos)&&ocrBrandPriceListBos.size()>0){
                    ocrVehicleRegistrationboRes.setOcrBrandPriceListBos(ocrBrandPriceListBos);
                }
            }else{
                ocrVehicleRegistrationboRes.setErrorCode(new JSONObject(result).getInt("error_code"));
                ocrVehicleRegistrationboRes.setErrorMsg(new JSONObject(result).getString("error_msg"));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return ocrVehicleRegistrationboRes;
    }

    @Override
    public VinBrandBoResq vinIdentifyVehicle(String vin) {
        VinBrandBoResq vinBrandBoResq=null;
        TVehicleInfo tVehicleInfo=tVehicleInfoMapper.selectOne(new LambdaQueryWrapper<TVehicleInfo>().eq(TVehicleInfo::getVin,vin).eq(TVehicleInfo::getDeleteFlag,1l));
        if(StringUtils.isNotNull(tVehicleInfo)){
            vinBrandBoResq=CommonUtil.objToObj(tVehicleInfo,VinBrandBoResq.class);
        }else{
           SortedMap<Object, Object> sortedMap = new TreeMap<Object, Object>() {
              {
                put("key", vinIdentifyKey);
                put("vin", vin);
             }
           };
        HttpResponse res = HttpRequest.
                post(vinIdentifyUrl)
                .body(JSONUtil.toJsonStr(sortedMap)).execute();
            logger.info("vin查询车辆信息返回结果：{}",res);
            if(res.getStatus()==200) {
                String resultJson = res.body();
                cn.hutool.json.JSONObject jsonObject=JSONUtil.parseObj(resultJson).getJSONObject("data");
                tVehicleInfo=new TVehicleInfo();
                vinBrandBoResq=new VinBrandBoResq();
                tVehicleInfo.setVehicleInfoUuid(CommonUtil.createUuid());
                tVehicleInfo.setDeleteFlag(1l);
                tVehicleInfo.setCreatedBy(SecurityUtils.getUsername());
                tVehicleInfo.setVin(vin);
                vinBrandBoResq.setVin(vin);
                tVehicleInfo.setBrandName(jsonObject.getStr("brand_name"));
                vinBrandBoResq.setBrandName(jsonObject.getStr("brand_name"));
                tVehicleInfo.setMatchingMode(jsonObject.getInt("matching_mode"));
                vinBrandBoResq.setMatchingMode(jsonObject.getInt("matching_mode"));
                tVehicleInfo.setIsCommercial(jsonObject.getInt("is_commercial"));
                vinBrandBoResq.setIsCommercial(jsonObject.getInt("is_commercial"));
                tVehicleInfo.setIsImport(jsonObject.getInt("is_import"));
                vinBrandBoResq.setIsImport(jsonObject.getInt("is_import"));
                tVehicleInfo.setManufacturer(jsonObject.getStr("manufacturer").replace("-","").replace("_",""));
                vinBrandBoResq.setManufacturer(jsonObject.getStr("manufacturer").replace("-","").replace("_",""));
                tVehicleInfo.setCid(jsonObject.getStr("cid"));
                vinBrandBoResq.setCid(jsonObject.getStr("cid"));
                tVehicleInfo.setSeriesName(jsonObject.getStr("series_name"));
                vinBrandBoResq.setSeriesName(jsonObject.getStr("series_name"));
                tVehicleInfo.setName(jsonObject.getStr("name"));
                vinBrandBoResq.setName(jsonObject.getStr("name"));
                tVehicleInfo.setYear(jsonObject.getStr("year"));
                vinBrandBoResq.setYear(jsonObject.getStr("year"));
                tVehicleInfo.setPrice(jsonObject.getStr("price"));
                vinBrandBoResq.setPrice(jsonObject.getStr("price"));
                tVehicleInfo.setMarketPrice(jsonObject.getStr("market_price"));
                vinBrandBoResq.setMarketPrice(jsonObject.getStr("market_price"));
                tVehicleInfo.setGearbox(jsonObject.getStr("gearbox"));
                vinBrandBoResq.setGearbox(jsonObject.getStr("gearbox"));
                tVehicleInfo.setGearnum(jsonObject.getStr("gearnum"));
                vinBrandBoResq.setGearnum(jsonObject.getStr("gearnum"));
                tVehicleInfo.setGeartype(jsonObject.getStr("geartype"));
                vinBrandBoResq.setGeartype(jsonObject.getStr("geartype"));
                tVehicleInfo.setEngineModel(jsonObject.getStr("engine_model"));
                vinBrandBoResq.setEngineModel(jsonObject.getStr("engine_model"));
                tVehicleInfo.setDrivenType(jsonObject.getStr("driven_type"));
                vinBrandBoResq.setDrivenType(jsonObject.getStr("driven_type"));
                tVehicleInfo.setDisplacementMl(jsonObject.getStr("displacement_ml"));
                vinBrandBoResq.setDisplacementMl(jsonObject.getStr("displacement_ml"));
                tVehicleInfo.setDisplacement(jsonObject.getStr("displacement"));
                vinBrandBoResq.setDisplacement(jsonObject.getStr("displacement"));
                tVehicleInfo.setEffluentStandard(jsonObject.getStr("effluent_standard"));
                vinBrandBoResq.setEffluentStandard(jsonObject.getStr("effluent_standard"));
                tVehicleInfo.setScale(jsonObject.getStr("scale"));
                vinBrandBoResq.setScale(jsonObject.getStr("scale"));
                tVehicleInfo.setCsjg(jsonObject.getStr("csjg"));
                vinBrandBoResq.setCsjg(jsonObject.getStr("csjg"));
                tVehicleInfo.setCms(jsonObject.getStr("cms"));
                vinBrandBoResq.setCms(jsonObject.getStr("cms"));
                tVehicleInfo.setZws(jsonObject.getStr("zws"));
                vinBrandBoResq.setZws(jsonObject.getStr("zws"));
                tVehicleInfo.setMarketDate(jsonObject.getStr("market_date"));
                vinBrandBoResq.setMarketDate(jsonObject.getStr("market_date"));
                tVehicleInfo.setStopDate(jsonObject.getStr("stop_date"));
                vinBrandBoResq.setStopDate(jsonObject.getStr("stop_date"));
                tVehicleInfo.setLength(jsonObject.getStr("length"));
                vinBrandBoResq.setLength(jsonObject.getStr("length"));
                tVehicleInfo.setWidth(jsonObject.getStr("width"));
                vinBrandBoResq.setWidth(jsonObject.getStr("width"));
                tVehicleInfo.setHigh(jsonObject.getStr("high"));
                vinBrandBoResq.setHigh(jsonObject.getStr("high"));
                tVehicleInfo.setWheelbase(jsonObject.getStr("wheelbase"));
                vinBrandBoResq.setWheelbase(jsonObject.getStr("wheelbase"));
                tVehicleInfo.setTrackfront(jsonObject.getStr("trackfront"));
                vinBrandBoResq.setTrackfront(jsonObject.getStr("trackfront"));
                tVehicleInfo.setTrackrear(jsonObject.getStr("trackrear"));
                vinBrandBoResq.setTrackrear(jsonObject.getStr("trackrear"));
                tVehicleInfo.setFullWeight(jsonObject.getStr("full_weight"));
                vinBrandBoResq.setFullWeight(jsonObject.getStr("full_weight"));
                tVehicleInfo.setFullWeightMax(jsonObject.getStr("full_weight_max"));
                vinBrandBoResq.setFullWeightMax(jsonObject.getStr("full_weight_max"));
                tVehicleInfo.setFrontTyreSize(jsonObject.getStr("front_tyre_size"));
                vinBrandBoResq.setFrontTyreSize(jsonObject.getStr("front_tyre_size"));
                tVehicleInfo.setRearTyreSize(jsonObject.getStr("rear_tyre_size"));
                vinBrandBoResq.setRearTyreSize(jsonObject.getStr("rear_tyre_size"));
                tVehicleInfo.setRlxs(jsonObject.getStr("rlxs"));
                vinBrandBoResq.setRlxs(jsonObject.getStr("rlxs"));
                tVehicleInfo.setRyxh(jsonObject.getStr("ryxh"));
                vinBrandBoResq.setRyxh(jsonObject.getStr("ryxh"));
                tVehicleInfo.setZdgl(jsonObject.getStr("zdgl"));
                vinBrandBoResq.setZdgl(jsonObject.getStr("zdgl"));
                tVehicleInfo.setFrontBrakeType(jsonObject.getStr("front_brake_type"));
                vinBrandBoResq.setFrontBrakeType(jsonObject.getStr("front_brake_type"));
                tVehicleInfo.setRearBrakeType(jsonObject.getStr("rear_brake_type"));
                vinBrandBoResq.setRearBrakeType(jsonObject.getStr("rear_brake_type"));
                tVehicleInfo.setParkingBrakeType(jsonObject.getStr("parking_brake_type"));
                vinBrandBoResq.setParkingBrakeType(jsonObject.getStr("parking_brake_type"));
                tVehicleInfo.setQfs(jsonObject.getStr("qfs"));
                vinBrandBoResq.setQfs(jsonObject.getStr("qfs"));
                tVehicleInfo.setGyfs(jsonObject.getStr("gyfs"));
                vinBrandBoResq.setGyfs(jsonObject.getStr("gyfs"));
                if(StringUtils.isNotNull(vinBrandBoResq.getIsImport())&&StringUtils.isNotEmpty(vinBrandBoResq.getBrandName())&&vinBrandBoResq.getIsImport()==1&&"大众".equals(vinBrandBoResq.getBrandName())){
                    vinBrandBoResq.setBrandName("进口大众");
                    tVehicleInfo.setBrandName("进口大众");
                }
                if( StringUtils.isNotEmpty(vinBrandBoResq.getManufacturer())&& UcarConstants.specialBrand.contains(vinBrandBoResq.getManufacturer())){
                    vinBrandBoResq.setBrandName(vinBrandBoResq.getManufacturer());
                    tVehicleInfo.setBrandName(vinBrandBoResq.getManufacturer());
                }
                tVehicleInfoMapper.insert(tVehicleInfo);
          }
        }
        List<OcrBrandPriceListBo>  ocrBrandPriceListBos=this.getOcrBrandPriceList(tVehicleInfo.getBrandName());
        if(StringUtils.isNotNull(ocrBrandPriceListBos)&&ocrBrandPriceListBos.size()>0){
            vinBrandBoResq.setOcrBrandPriceListBos(ocrBrandPriceListBos);
        }
        return vinBrandBoResq;
    }


    /**
     * 从用户的AK，SK生成鉴权签名（Access Token）
     *
     * @return 鉴权签名（Access Token）
     * @throws IOException IO异常
     */
    private String getAccessToken()  {
        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + ocrAppKey
                + "&client_secret=" + ocrSecretKey);
        Request request = new Request.Builder()
                .url("https://aip.baidubce.com/oauth/2.0/token")
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .build();
        Response response = null;
        try {
            response = HTTP_CLIENT.newCall(request).execute();
            return new JSONObject(response.body().string()).getString("access_token");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
